Random.self_init ()

let n_manches = 15

let id x = x

let permutation n =
  let tab = Array.init n (id) in
  let inserer k =
    let place = Random.int (k + 1) in
    let aux = tab.(k) in
    let () = tab.(k) <- tab.(place) in
    tab.(place) <- aux
  in
  for k=1 to n-1 do
    inserer k
  done ;
  tab

type distribution =
  {
    cartes_joueurs: Carte.carte list array;
    chien: Carte.carte array;
  }

let compter_atouts =
  let rec aux n = function
    | [] -> n
    | a :: b when Carte.est_atout a ->
       aux (n + 1) b
    | _ :: b -> aux n b
  in
  aux 0

let petit_present = List.exists ((=) Carte.petit)
let excuse_presente = List.exists ((=) Carte.excuse)

let petit_sec distrib =
  let examiner_main jeu =
    let nombre_atouts = compter_atouts jeu in
    let petit_present = petit_present jeu in
    let excuse_absente = not (excuse_presente jeu) in
    nombre_atouts = 1 && petit_present && excuse_absente
  in
  let ps = Array.map (examiner_main) distrib.cartes_joueurs in
  Array.fold_left (||) false ps

let rec distribuer () =
  let cartes = Array.map (Carte.carte_of_int) (permutation 78) in
  let distrib =
    {
      cartes_joueurs = Array.init 5 (fun i -> Array.to_list (Array.sub cartes (15 * i) 15)) ;
      chien = Array.sub cartes 75 3
    }
  in
  let d =
    if petit_sec distrib then distribuer ()
    else distrib
  in
  d

type serveur = 
  {
    identifies: (string, Tarotv.t) Hashtbl.t;
    mutable finisseur : string array -> unit;
    mutable suiveur: string -> string -> string -> unit; (* nom du client, type, message de
							    débogage *)
    mutable envoyer: string -> Protocole.msg -> unit;
    mutable deconnecter: string -> unit;
  }

let make () =
  {
    identifies = Hashtbl.create 1;
    finisseur = (fun _ -> failwith "Not specified");
    suiveur = 
      (fun _ _ _ -> failwith "Not specified");
    envoyer =
      (fun _ _ -> failwith "Not specidied");
    deconnecter =
      (fun _ -> failwith "Not specified")
  }

let set_finisseur serveur fonction =
  serveur.finisseur <-
    fun noms ->
    try fonction noms with _ -> ()

let set_suiveur serveur fonction =
  serveur.suiveur <- fun nom msg cause ->
    try fonction nom msg cause with _ -> ()

let set_envoyer serveur fonction =
  let envoyer_assimiler nom msg =
    let client = Hashtbl.find serveur.identifies nom in
    let open Protocole in
    let () = match msg with
      | Deconnexion -> () (* Le serveur demande à fermer la connexion. *)
      | ErreurProtocole | Refuse -> 
	 let () = Tarotv.assimiler_information_erreur client in
	 serveur.suiveur nom "refuse" "La demande du client a été refusée."
      | Identifier _ | Inviter _ -> ()
      | Entree str -> 
	 let () = Tarotv.assimiler_information_entree client str in
	 serveur.suiveur nom "entree" ("Le joueur "^str^" est maintenant disponible.")
      | Sortie str ->
	 let () = Tarotv.assimiler_information_sortie client str in
	 serveur.suiveur nom "sortie" ("Le joueur "^str^" n'est plus disponible.")
      | Noms tab ->
	 let () = Tarotv.assimiler_information_noms client tab in
	 serveur.suiveur nom "noms"
	   ("Je joue avec [|"
	    ^(String.concat "; " 
		(Array.to_list tab))
	    ^"|].")
      | Numero x ->
	 let () = Tarotv.assimiler_information_numero client x in
	 serveur.suiveur nom "numero"
	   (match x with
	   | 0 -> "Je joue en premier."
	   | 1 -> "Je joue en deuxième."
	   | 2 -> "Je joue en troisième."
	   | 3 -> "Je joue en quatrième."
	   | 4 -> "Je joue en dernier."
	   | x -> "Je joue en "^(string_of_int x)^"ième.")
      | Distribution cartes ->
	 let () = Tarotv.assimiler_information_distribution client (Array.to_list cartes)
	 in
	 serveur.suiveur nom "distribution" 
	   ("J'ai reçu mes cartes : "
	    ^(String.concat ", "
		(List.map (Carte.string_of_carte)
		   (Array.to_list cartes))))
      | Prise _ -> ()
      | Contrat x ->
	 let ench = Array.init 5 (Tarotv.enchere_de client) in
	 let () = Tarotv.assimiler_information_contrat client x in
	 Array.iteri (fun i ancienne_enchere ->
	   let nouvelle_enchere = Tarotv.enchere_de client i in
	   if nouvelle_enchere <> ancienne_enchere then
	     let nom_joueur = (Tarotv.mes_adversaires client).(i) in
	     let prise = match x with
	       | 0 -> "passe" | 1 -> "prise" | 2 -> "garde" | 3 -> "garde sans"
	       | 4 -> "garde contre" | x -> ("fait l'enchère "^(string_of_int x)) in
	     let message = nom_joueur^" "^prise^"." in
	     serveur.suiveur nom "contrat" message)
	   ench
      | Appel -> 
	 let () = Tarotv.assimiler_information_appel client in
	 serveur.suiveur nom "appel" "Je dois faire un appel." 
      | Appeler _ -> ()
      | ContratFinal (preneur, prise, appel) ->
	 let () = Tarotv.assimiler_information_contrat_final client preneur prise appel in
	 let nom_preneur = (Tarotv.mes_adversaires client).(preneur) in
	 let message = nom_preneur^" appelle la carte "^(Carte.string_of_carte appel)^"." in
	 serveur.suiveur nom "contrat_final" message
      | Chien tab ->
	 let () = Tarotv.assimiler_information_chien client (Array.to_list tab) in
	 serveur.suiveur nom "chien" "Le chien a été dévoilé."
      | Ecart tab -> ()
      | Atout liste -> 
	 let () = Tarotv.assimiler_information_atout_au_chien client liste in
	 serveur.suiveur nom "atout" "Un ou des atout(s) a (ont) été mis au chien."
      | Jeu ->
	 let () = Tarotv.assimiler_information_jeu client in
	 serveur.suiveur nom "jeu" "Le jeu commence."
      | Requete _ -> ()
      | Carte c ->
	 let () = Tarotv.assimiler_information_carte client c in
	 serveur.suiveur nom "carte" ("La carte '"^(Carte.string_of_carte c)^"' est jouée.")
      | Pli x ->
	 let () = Tarotv.assimiler_information_pli client x in
	 serveur.suiveur nom "pli" "Pli terminé."
      | Resultat tab ->
	 let () = Tarotv.assimiler_information_resultat client tab in
	 serveur.suiveur nom "resultat" "Manche terminée."
    in
    fonction nom msg
  in
  serveur.envoyer <- envoyer_assimiler

let set_deconnecter serveur fonction =
  serveur.deconnecter <- fonction

let dump serveur client =
  (* let () = Printf.printf "Dump de %s.\n%!" client in *)
  let c = Hashtbl.find serveur.identifies client in
  Tarotv.etat_de c

let noms serveur = Hashtbl.fold (fun n _ liste -> n :: liste) serveur.identifies []

let enregistrer_deconnexion serveur nom =
  (* était-il en jeu ? *)
  (* let () = Printf.printf "J'officialise la déconnexion de %s.\n" nom in *)
  try
    let c = Hashtbl.find serveur.identifies nom in
    (* let () = Printf.printf "Je le connais.\n%!" in *)
    if Tarotv.en_jeu c then
      (* let () = Printf.printf "Il était en train de jouer.\n%!" in *)
      let adversaires = Tarotv.mes_adversaires c in
      (* let () = Printf.printf "Il avait %d adversaires.\n%!"  *)
      (* 	(Array.length adversaires) in *)
      (* On informe de la déconnexion effective *)
      let () = Tarotv.assimiler_information_deconnexion c in
      let () = serveur.suiveur nom "deconnexion" "Le joueur s'est déconnecté." in
      let () = Hashtbl.remove serveur.identifies nom in
      (* S'ils existent encore, on déconnecte tous les adversaires *)
      Array.iter
	(fun nom -> 
	  (* let () = Printf.printf "Je dois également déconnecter %s...\n%!" nom in *)
	  if Hashtbl.mem serveur.identifies nom then
	    (* let () = Printf.printf "Il existe.\n%!" in *)
	    serveur.deconnecter nom
	  else 
	    (* let () = Printf.printf "Je ne le connais pas.\n%!" in *)
	    ()) adversaires 
    else
      (* let () = Printf.printf "Ce type n'était pas en jeu.\n%!" in *)
    (* On doit informer de la sortie du joueur *)
      let () = serveur.suiveur nom "deconnexion" "Le joueur s'est déconnecté." in
      let () = Hashtbl.remove serveur.identifies nom in
    (* On compose le message *)
      let msg = Protocole.Sortie nom in
    (* On l'envoie à tous les clients hors jeu, en le précisant au suiveur *)
      let () = Hashtbl.iter 
	(fun informe client ->
	  (* let () = Printf.printf "Dois-je envoyer \"Sortie %s\" à %s ?\n%!"  *)
	  (*   nom informe in *)
	  if not (Tarotv.en_jeu client) then
	    (* let () = Printf.printf "Oui.\n%!" in *)
	    (* On envoie effectivement le message *)
	    serveur.envoyer informe msg
	  else 
	    (* let () = Printf.printf "Non.\n%!" in  *)
	    ()) serveur.identifies
      in
      ()
  with
  | Not_found -> 
     (* let () = Printf.printf "Je ne le connais pas...\n%!" in *)
     () (* rien à faire *)

let partie_interessante chaine =
  let rec taille_nom i =
    if i >= String.length chaine then i
    else if chaine.[i] = (char_of_int 0) then (* Fin du mot *) i
    else taille_nom (i + 1)
  in
  String.sub chaine 0 (taille_nom 0)

let nouveau_client serveur peut_accepter_nom 
    valider_identification = function
  | Protocole.Identifier nom ->
     let nom_tronque = partie_interessante nom in
     let ok_moi = not (Hashtbl.mem serveur.identifies nom_tronque) in
     let ok =
       if ok_moi then
	 peut_accepter_nom nom_tronque
       else false
     in
     if ok then
       let nouveau_client = Tarotv.make () in
       let () = Tarotv.assimiler_information_connexion nouveau_client in
       let () = Hashtbl.add serveur.identifies nom_tronque nouveau_client in
       (* let () = Printf.printf "J'ai ajouté le client %s.\n" nom_tronque in *)
       (* On valide pour la fonction appelante... *)
       let () = valider_identification (Some nom_tronque) in
       (* On doit assimiler la requête, pour que ce soit sensé de l'accepter... *)
       let () = Tarotv.assimiler_requete_identifier nouveau_client
	 nom_tronque in
       (* Identification acceptée. On envoie à tous les joueurs non en *)
       (* jeu la nouvelle, et on lui présente ce nouveau type... *)
       let () = Hashtbl.iter
	 (fun autre client ->
	   if not (Tarotv.en_jeu client) && autre <> nom_tronque then
	     (* Attention : on ne doit pas informer le nouveau client de sa présence ! *)
	     let () = serveur.envoyer autre 
	       (Protocole.Entree nom_tronque) in
	     let () = serveur.envoyer nom_tronque
	       (Protocole.Entree autre) in
	     ()
	   else ())
	 serveur.identifies in
       (* Finalement, on l'informe qu'il est là. *)
       let () = serveur.envoyer nom_tronque (Protocole.Entree
					       nom_tronque) in
       ()
     else
       (* On refuse à cet inconnu *)
       valider_identification None
  | _ -> valider_identification None

let preparer_partie serveur noms (* dans l'ordre *) =
  (* D'abord, on envoie le message "noms"*)
  let msg = Protocole.Noms noms in
  let () = Array.iter (fun nom -> serveur.envoyer nom msg) noms in
  (* Ensuite, "numero" *)
  let () = Array.iteri
    (fun i nom -> serveur.envoyer nom (Protocole.Numero i))
    noms
  in
  (* Puis enfin, "distribution", en oubliant le chien (on pourra le retrouver) *)
  let d = distribuer () in
  let () =
    Array.iteri
      (fun i jeu ->
       serveur.envoyer
	 noms.(i) 
		(Protocole.Distribution
		   (Array.of_list jeu)))
      d.cartes_joueurs in
  (* let () = print_endline "Distribution envoyée." in *)
  ()

let cartes_hors_partie serveur un_participant =
  let un_client = Hashtbl.find serveur.identifies un_participant in
  let noms = Tarotv.mes_adversaires un_client in
  let clients = Array.map (Hashtbl.find serveur.identifies) noms in
  let absentes = Array.init 78 (fun i -> [Carte.carte_of_int i]) in (* à biffer *)
  let () = Array.iter (fun client ->
    List.iter 
      (fun carte -> let i = Carte.int_of_carte carte in
		    absentes.(i) <- [])
      (Tarotv.mon_jeu client))
    clients 
  in
  Array.fold_right (@) absentes []
  
       
let assimiler_message serveur nom msg =
  let client = Hashtbl.find serveur.identifies nom in
  let open Protocole in
  try
  match msg with
  | Deconnexion -> enregistrer_deconnexion serveur nom
  | ErreurProtocole
  | Refuse 
  | Entree _
  | Sortie _
  | Noms _
  | Numero _
  | Distribution _
  | Contrat _
  | Appel 
  | ContratFinal _
  | Chien _
  | Atout _
  | Jeu 
  | Carte _
  | Pli _
  | Resultat _ -> serveur.envoyer nom (Protocole.ErreurProtocole)
  | Identifier nom_demande ->
     let nom_tronque = partie_interessante nom_demande in
     let () = Tarotv.assimiler_requete_identifier client nom_tronque in
     (* requête qu'on refuse tout de suite *)
     serveur.envoyer nom Protocole.ErreurProtocole
  | Inviter noms ->
     let () = serveur.suiveur nom "invitater"
       ("Invitation de "
	^(String.concat ", " (Array.to_list (Array.map (partie_interessante) noms)))
	^".")
     in
     (* si on est en jeu, c'est une erreur de protocole *)
     let noms = Array.map (partie_interessante) noms in
     let () = Tarotv.assimiler_requete_inviter client (Array.to_list noms) in
     if Tarotv.en_jeu client then
       (* let () = Printf.printf "L'invitation est refusée car le client est en jeu.\n" in *)
       serveur.envoyer nom (Protocole.ErreurProtocole)
     else
       let noms_tous = nom :: (Array.to_list noms) in
       (* let cinq_noms = *)
       (* 	 let vide = Array.make 5 "<personne>" in *)
       (* 	 let n = Array.of_list noms_tous in *)
       (* 	 let () = Array.blit n 0 vide 0 (min 5 (Array.length n)) in *)
       (* 	 vide *)
       (* in *)
       (* let () = Printf.printf "Le client %s veut jouer avec %s, %s, %s, %s et %s.\n" *)
       (* 	 nom cinq_noms.(0) cinq_noms.(1) cinq_noms.(2) cinq_noms.(3) cinq_noms.(4) *)
       (* in *)
       (* On vérifie qu'ils sont tous différents *)
       let rec eliminer_doublons = function
	 | [] -> []
	 | a :: b when not (List.exists ((=) a) b) -> a :: (eliminer_doublons b)
	 | _ :: b -> eliminer_doublons b
       in
       let noms_filtres = eliminer_doublons noms_tous in
       if List.length noms_filtres = 5 then
	 (* Ils doivent tous être disponibles *)
	 try
	   let joueurs = List.map (Hashtbl.find serveur.identifies) noms_filtres in
	   let occupe = List.map (Tarotv.en_jeu) joueurs in
	   if not (List.fold_left (||) false occupe) then
	     (* On mélange les participants *)
	     let noms_non_ordonnes = Array.of_list noms_filtres in
	     let permutation = permutation 5 in
	     let noms_ordonnes = Array.init 5 (fun i -> 
	       noms_non_ordonnes.(permutation.(i))) in
	     (* On lance la partie ! *)
	     let () = preparer_partie serveur noms_ordonnes in
	     (* On fait sortir les gens *)
	     let messages_sorties =
	       List.map
		 (fun n -> Protocole.Sortie n)
		 noms_filtres
	     in
	     let () = Hashtbl.iter
	       (fun nom client ->
		 if not (Tarotv.en_jeu client) then
		   List.iter (serveur.envoyer nom) messages_sorties		      
		 else ()) 
	       serveur.identifies in
	     ()
	   else serveur.envoyer nom (Protocole.Refuse)
	 with
	 | Not_found -> serveur.envoyer nom (Protocole.Refuse)
       else 
	 serveur.envoyer nom (Protocole.Refuse)
  (* Pour toutes les requêtes de jeu, on commence par vérifier si le client doit faire cette requête avant de l'assimiler, car par exemple, on ne doit pas jouer une carte quand une requête est en cours de traitement. *)
  | Prise x ->
     let () = serveur.suiveur nom
       "prise"
       ("Demande à "
	^(match x with 0 -> "passer" | 1 -> "priser" | 2 -> "garder"
	| 3 -> "garder sans le chien" | 4 -> "garder contre le chien"
	| x -> ("faire l'enchère "^(string_of_int x)))
	^".")
     in
     if Tarotv.doit_priser client then
       let () = Tarotv.assimiler_requete_prise client x in
       let (_, max) = Tarotv.enchere_maximale client in
       if x = 0 || x > max then
	 (* On envoie : contrat *)
	 let () = Array.iter
	   (fun nom -> serveur.envoyer nom (Protocole.Contrat x))
	   (Tarotv.mes_adversaires client) in
	 (* Si tout le monde a fait une enchère, quelqu'un doit faire un appel *)
	 let encheres = Array.init 5 (Tarotv.enchere_de client) in
	 let encheres_faites = Array.map ((<>) None) encheres in
	 if Array.fold_left (&&) true encheres_faites then
	   let (preneur, ench) = Tarotv.enchere_maximale client in
	   if ench = 0 then
	     (* On redistribue *)
	     let ancien_noms = Tarotv.mes_adversaires client in
	     let () = serveur.finisseur ancien_noms in
	     preparer_partie serveur
	       (Array.init 5 (fun i -> ancien_noms.((i + 1) mod 5)))
	   else
	     let nom_preneur = (Tarotv.mes_adversaires client).(preneur) in
	     serveur.envoyer nom_preneur (Protocole.Appel)
	 else ()
       else
	 serveur.envoyer nom (Protocole.Refuse)
     else 
       let () = Tarotv.assimiler_requete_prise client x in
       serveur.envoyer nom (Protocole.ErreurProtocole)
  | Appeler carte ->
     let () = serveur.suiveur nom "appeler"
       ("Demande à appeler "^(Carte.string_of_carte carte)^".") in
     if Tarotv.doit_appeler client then
       let () = Tarotv.assimiler_requete_appel client carte in
       if Tarotv.peut_appeler client carte then
	 (* On envoie le contrat final *)
	 let (preneur, enchere) = Tarotv.enchere_maximale client in
	 let () = Array.iter
	   (fun nom -> serveur.envoyer nom 
	     (Protocole.ContratFinal (preneur, enchere, carte)))
	   (Tarotv.mes_adversaires client)
	 in
	 (* Chien ? *)
	 if enchere <= 2 (* garde sans *) then 
	   (* On doit déterminer le chien *)
	   let chien = Array.of_list (cartes_hors_partie serveur nom) in
	   (* On l'envoie *)
	   Array.iter
	     (fun nom -> serveur.envoyer nom (Protocole.Chien chien))
	     (Tarotv.mes_adversaires client)
	 else
	   (* On envoie jeu *)
	   Array.iter
	     (fun nom -> serveur.envoyer nom Protocole.Jeu)
	     (Tarotv.mes_adversaires client)
       else
	 serveur.envoyer nom Protocole.Refuse
     else
       let () = Tarotv.assimiler_requete_appel client carte in
       serveur.envoyer nom Protocole.ErreurProtocole
  | Ecart cartes ->
     let cartes = Array.to_list cartes in
     let noms_cartes = List.map (Carte.string_of_carte) cartes in
     let () = serveur.suiveur nom "ecart"
       ("Demande à écarter "^(String.concat ", " noms_cartes)^".") in
     if Tarotv.doit_ecarter client then
       let () = Tarotv.assimiler_requete_ecart client cartes in
       if Tarotv.peut_ecarter client cartes then
	 (* On sélectionne les atouts *)
	 let atouts = List.filter (Carte.est_atout) cartes in
	 let () =
	   match atouts with
	   | [] -> ()
	   | liste ->
	      Array.iter
		(fun nom -> serveur.envoyer nom (Protocole.Atout liste))
		(Tarotv.mes_adversaires client)
	 in
	   (* On envoie "jeu" *)
	 Array.iter
	   (fun nom -> serveur.envoyer nom Protocole.Jeu)
	   (Tarotv.mes_adversaires client)
       else
	 serveur.envoyer nom Protocole.Refuse
     else
       let () = Tarotv.assimiler_requete_ecart client cartes in
       serveur.envoyer nom Protocole.ErreurProtocole
  | Requete carte ->
     let () = serveur.suiveur nom "requete"
			      ("Demande à jouer "^(Carte.string_of_carte carte)^".") in
     if Tarotv.doit_jouer client then
       if Tarotv.peut_jouer client carte then
	 let () = Tarotv.assimiler_requete_carte client carte in
	 (* On envoie le message carte *)
	 let () = Array.iter
	   (fun nom -> serveur.envoyer nom (Protocole.Carte carte))
	   (Tarotv.mes_adversaires client)
	 in
	 (* On termine le pli *)
	 let () =
	   if Tarotv.pli_termine client then
	     match Tarotv.joueur_maitre client with
	     | None -> failwith "Pas de joueur maître !"
	     | Some j ->
		Array.iter
		  (fun nom ->
		   (* let () = Printf.printf "Envoi de pli...\n%!" in *)
		   let () = serveur.envoyer nom (Protocole.Pli j) in
		   (* let () = Printf.printf "Message envoyé.\n%!" in *)
		   ())
		  (Tarotv.mes_adversaires client)
	   else ()
	 in
	 (* On recommence la partie *)
	 let () =
	   let () = Printf.printf "Nombre de plis joués : %d.\n%!"
	   			  (Tarotv.nombre_plis_joues client) in
	   if Tarotv.nombre_plis_joues client >= 15 then
	     let (preneur, i_preneur) = match Tarotv.preneur client with
	       | None -> failwith "Impossible de commencer une nouelle partie. Pas de preneur pour la précédente."
	       | Some p -> 
		  try
		    (Hashtbl.find serveur.identifies  (Tarotv.mes_adversaires client).(p), p)
		  with Not_found -> failwith "Même pas cap de récupérer le preneur."
	     in
	     let () = Printf.printf "Le preneur est %s (%d).\n%!"
	     			    (Tarotv.mon_nom preneur) i_preneur in
	     let i_appele = match Tarotv.joueur_appele client with
	       | None -> i_preneur (* Cas garde sans / contre, la carte appelée est dans le chien *)
	       | Some j -> j
	     in
	     let () = Printf.printf "Le joueur appelé est %d.\n%!" i_appele in
	     let (dp, bouts) = Tarotv.points preneur (Tarotv.joueur_appele preneur) in
	     let () = Printf.printf "Le preneur a fait %f points pour %d bouts.\n%!"
	     			    ((float_of_int dp) /. 2.) bouts
	     in
	     let barre = 2 *
	       (match bouts with
	       | 0 -> 56 (* *2 : ok *)
	       | 1 -> 51
	       | 2 -> 41
	       | 3 -> 36
	       | x -> failwith ("Scoop : il y a "^(string_of_int x)^" bouts dans le jeu de tarot.")) in
	     let () = Printf.printf "Il faut faire %f points.\n%!"
	     			    ((float_of_int barre) /. 2.) in
	     let realise = dp >= barre in
	     (* On pard de +- 25 selon qu'on réalise le contrat ou qu'on chute, on ajoute le nombre de points de l'attaque moins la barre *)
	     let points_base = 
	       let depart = if realise then 50 else -50 in
	       let demis = depart + dp - barre in
	       if demis mod 2 = 0 then demis / 2
	       else if realise then (demis + 1) / 2
	       else (demis - 1) / 2
	     in
	     let () = Printf.printf "On part de %d points.\n%!" points_base in
	     (* Petit au bout : on rajoute ou enlève 10 points. *)
	     let points_pab =
	       match Tarotv.petit_au_bout client with
	       | None -> points_base
	       | Some `Attaque -> points_base + 10
	       | Some `Defense -> points_base - 10
	     in
	     let () = Printf.printf
	     		"Après tenue en compte du petit au bout, on arrive à %d/\n%!"
	     		points_pab in
	     (* Multiplication : garde x2, sans x4, contre x6 *)
	     let points_multiplies = 
	       match Tarotv.enchere_de preneur i_preneur with
	       | None -> failwith "Le preneur n'a même pas fait d'enchère........"
	       | Some 0 -> failwith "Le preneur a pris en passant.........."
	       | Some 1 -> points_pab
	       | Some 2 -> 2 * points_pab
	       | Some 3 -> 4 * points_pab
	       | Some 4 -> 6 * points_pab
	       | Some x -> failwith ("Le preneur a fait une drôle de prise : "^(string_of_int x))
	     in
	     let () = Printf.printf "Après multiplication, on arrive à %d points.\n%!"
	     			    points_multiplies in
	     (* On envoie lé résoultat *)
	     let resultats = Array.make 5 (-points_multiplies) in
	     (* Le joueur appelé reçoit +points_multiplies *)
	     let () = resultats.(i_appele) <- points_multiplies
	     in
	     (* Le preneur enlève algébriquement la somme des points *)
	     let somme = Array.fold_left (+) 0 resultats in
	     let () = resultats.(i_preneur) <- resultats.(i_preneur) - somme
	     in
	     let () = Array.iter
	       (fun nom -> serveur.envoyer nom (Protocole.Resultat resultats))
	       (Tarotv.mes_adversaires client)
	     in
	     let ancien_noms = Tarotv.mes_adversaires client in
	     let () = serveur.finisseur ancien_noms in
	     (* On redistribue *)
	     preparer_partie serveur
	       (Array.init 5 (fun i -> ancien_noms.((i + 1) mod 5)))
	   else ()
	 in
	 ()
       else
	 let () = Tarotv.assimiler_requete_carte client carte in
	 serveur.envoyer nom Protocole.Refuse
     else
       let () = Tarotv.assimiler_requete_carte client carte in
       serveur.envoyer nom Protocole.ErreurProtocole
  with exc ->
       let () = Printf.printf "Exception : %s.\n%!"
			      (Printexc.to_string exc) in
       raise exc
